#include <cstdarg>
#include <algorithm> 
#include <sys/stat.h>
#include <cstring>
#include <log.h>
#include <logFile.h>
#include <utils.h>
#include <mutex>

namespace Ilog
{

    LOCAL std::atomic<UINT>     logModuleInstanceGeneratedId = 0;
    LOCAL std::mutex            logModuleInstanceLock;
    LOCAL std::map<int, LogPtr> logModuleList;

    LOCAL inline size_t logModuleListSize()
    {
        std::lock_guard<std::mutex> lock(logModuleInstanceLock);
        return logModuleList.size();
    }

    LOCAL inline void logModuleListClear()
    {
        std::lock_guard<std::mutex> lock(logModuleInstanceLock);
        return logModuleList.clear();
    }

    LOCAL inline void logModuleListInsert(int& logInst, LogPtr logIter)
    {
        std::lock_guard<std::mutex> lock(logModuleInstanceLock);
        logInst = logModuleInstanceGeneratedId++;
        logModuleList[logInst] = logIter;
    }

    LOCAL inline void logModuleListErase(int logInst)
    {
        std::lock_guard<std::mutex> lock(logModuleInstanceLock);
        logModuleList.erase(logInst);
    }

    LOCAL inline LogPtr logModuleListQuery(int logInst)
    {
        COND_CHECK_RET_VAL(logModuleListSize() == 0, nullptr);

        std::lock_guard<std::mutex> lock(logModuleInstanceLock);
        
        auto logIter = logModuleList.find(logInst);

        COND_CHECK_RET_VAL(logIter != logModuleList.end(), logIter->second);

        return nullptr;
    }

    LogPtr logModuleGet(int logInst)
    {
        COND_CHECK_RET_VAL(logModuleListSize() == 0, nullptr);

        return logModuleListQuery(logInst);
    }
    STATUS forEachLogModule(FUNCPTR func, void * arg)
    {
        std::lock_guard<std::mutex> lock(logModuleInstanceLock);
        for (const auto& iter : logModuleList) 
        {
            func(arg, iter);
        }
        return OK;
    }

    STATUS logHexdump(int logInst, const char *name, uint8_t width, const char *buf, uint16_t size)
    {
        auto logIter = logModuleGet(logInst);

        COND_CHECK_RET_ERROR(logIter == nullptr);

        logIter->hexdump(name, width, buf, size);
        return OK;
    }

    STATUS logInitial()
    {
        int logInst = 0;
        logModuleListClear();
        return logModuleRegister (logInst, nullptr) ;
    }

    STATUS logRelease()
    {
        logModuleListClear();
        return OK;
    }

    STATUS logModuleRegister(int& logInst, const char *file, int fileCnt, int fileSize, int level)
    {
        COND_CHECK_RET_ERROR(logModuleListSize() > MODULE_MAX_NUM);

        LogPtr logIter = std::make_shared<LogFile>(file, fileCnt, fileSize, level);

        COND_CHECK_RET_ERROR(logIter == nullptr);

        logModuleListInsert(logInst, logIter);

        return OK;
    }
    STATUS logModuleUnregister(int logInst)
    {
        logModuleListErase(logInst);
        return OK;
    }
} // namespace Ilog
